package bancosys.tec.utils.date;

import java.util.Calendar;

/**
 * Guarda um horario, mantem sempre a data zerada.
 * 
 * @created Dec 4, 2006
 * @author Gustavo Almeida
 */
public class Time extends java.sql.Time implements Cloneable {
    private transient Calendar calendar;

    /**
     * Contrutor.
     * 
     * @param date data
     */
    public Time(Calendar date) {
        this(date.getTimeInMillis());
    }

    /**
     * Construtor.
     * 
     * @param date em millis
     */
    public Time(long date) {
        super(date);
        this.getCalendar().setTimeInMillis(date);
        this.updateTime();
    }

    /**
     * Construtor, constroi com data atual.
     */
    public Time() {
        this(new java.util.Date().getTime());
    }

    /**
     * Construtor.
     * 
     * @param date data
     */
    public Time(java.util.Date date) {
        this(date.getTime());
    }

    /**
     * Construtor.
     * 
     * @param hour hora.
     * @param minute minuto.
     * @param second segundos.
     */
    public Time(int hour, int minute, int second) {
        super(0);
        Calendar cal = this.getCalendar();
        cal.set(Calendar.HOUR_OF_DAY, hour);
        cal.set(Calendar.MINUTE, minute);
        cal.set(Calendar.SECOND, second);
        this.updateTime();
    }

    /**
     * Adiciona <code>amount</code> horas no horario atual, modificando a instancia atual.
     * 
     * @param amount quantidade de horas a serem adicionadas.
     * @return devolve essa mesma instância.
     */
    public Time addHours(int amount) {
        return this.addField(Calendar.HOUR_OF_DAY, amount);
    }

    /**
     * Adiciona <code>amount</code> minutos no horario atual, modificando a instancia atual.
     * 
     * @param amount quantidade de minutos a serem adicionados.
     * @return devolve essa mesma instância.
     */
    public Time addMinutes(int amount) {
        return this.addField(Calendar.MINUTE, amount);
    }

    /**
     * Adiciona <code>amount</code> segundos no horario atual, modificando a instancia atual.
     * 
     * @param amount quantidade de segundos a serem adicionados.
     * @return devolve essa mesma instância.
     */
    public Time addSeconds(int amount) {
        return this.addField(Calendar.SECOND, amount);
    }

    /**
     * Devolve as horas.
     * 
     * @return as horas.
     */
    @Override
    public int getHours() {
        return this.getAndSetCalendar().get(Calendar.HOUR_OF_DAY);
    }

    /**
     * Devolve os minutos.
     * 
     * @return os minutos.
     */
    @Override
    public int getMinutes() {
        return this.getAndSetCalendar().get(Calendar.MINUTE);
    }

    /**
     * Devolve os segundos.
     * 
     * @return os segundos.
     */
    @Override
    public int getSeconds() {
        return this.getAndSetCalendar().get(Calendar.SECOND);
    }

    /**
     * Devolve um clone dessa instância.
     * 
     * @return um clone dessa instância.
     */
    @Override
    public Object clone() {
        return new Time(this.getTime());
    }

    /**
     * Devolve a um calendar representando essa data, método provisório deve ser usado apensa durante a migração de Calendar para Date.
     * 
     * @deprecated
     * @return um calendar representando essa data
     */
    @Deprecated
    public Calendar asCalendar() {
        Calendar ret = Calendar.getInstance();
        ret.setTime(this);
        return ret;
    }

    /**
     * Devolve o calendar onde o horario é manipulado.
     * 
     * @return o calendar onde o horario é manipulado.
     */
    private Calendar getCalendar() {
        if (this.calendar == null) {
            this.calendar = Calendar.getInstance();
        }
        return this.calendar;
    }

    /**
     * Retorna o calendar da instância com a data setada.
     * 
     * @return o calendar da instância com a data setada.
     */
    private Calendar getAndSetCalendar() {
        Calendar cal = this.getCalendar();
        cal.setTime(this);
        return cal;
    }

    /**
     * Zera logicamente os campos de ano, mes, dia e millisegundos.
     */
    private void updateTime() {
        Calendar cal = this.getCalendar();
        cal.set(Calendar.YEAR, 1);
        cal.set(Calendar.MONTH, 1);
        cal.set(Calendar.DAY_OF_MONTH, 1);
        cal.set(Calendar.MILLISECOND, 0);
        this.setTime(cal.getTimeInMillis());
    }

    /**
     * Método acessório para manipular campos da instância de time corrente.
     * 
     * @param field a representação de campo no Calendar.
     * @param amount a quantidade a ser adicionada no campo do time
     * @return A instância de data corrente, com os campos adicionados.
     */
    private Time addField(int field, int amount) {
        Calendar cal = this.getAndSetCalendar();
        cal.add(field, amount);
        this.updateTime();
        return this;
    }
}
